{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Action2  使用Google  Colab编辑器，对MovieLens数据集进行评分预测，计算RMSE（使用funkSVD, BiasSVD，SVD++）      \n",
    "1、使用Colab完成3种算法在MovieLens的评分预测（20points）     2、使用Surprise以外的工具(+5points)    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 34
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 59267,
     "status": "ok",
     "timestamp": 1600231113106,
     "user": {
      "displayName": "yusheng zhou",
      "photoUrl": "",
      "userId": "10321925231562651610"
     },
     "user_tz": -480
    },
    "id": "CmPNo43TMgxc",
    "outputId": "911258e9-deb6-44cf-ffa0-074cb7c0ec00"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mounted at /content/drive\n"
     ]
    }
   ],
   "source": [
    "# from google.colab import drive\n",
    "# drive.mount('/content/drive')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 1194,
     "status": "ok",
     "timestamp": 1600232093247,
     "user": {
      "displayName": "yusheng zhou",
      "photoUrl": "",
      "userId": "10321925231562651610"
     },
     "user_tz": -480
    },
    "id": "l1ahlNHiORxu"
   },
   "outputs": [],
   "source": [
    "# import os\n",
    "# os.chdir(\"/content/drive/My Drive/Colab Notebooks/Bi-IV/MovieLens_rating_predict\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 5031,
     "status": "ok",
     "timestamp": 1600233131247,
     "user": {
      "displayName": "yusheng zhou",
      "photoUrl": "",
      "userId": "10321925231562651610"
     },
     "user_tz": -480
    },
    "id": "DlqjOAfD65r-"
   },
   "outputs": [],
   "source": [
    "#!pip install surprise\n",
    "from surprise import SVD,SVDpp\n",
    "from surprise import Dataset\n",
    "from surprise.model_selection import cross_validate\n",
    "from surprise import Reader\n",
    "from surprise import accuracy\n",
    "from surprise.model_selection import KFold\n",
    "import pandas as pd\n",
    "import time\n",
    "\n",
    "\n",
    "# 数据读取\n",
    "reader = Reader(line_format='user item rating timestamp', sep=',', skip_lines=1)\n",
    "data = Dataset.load_from_file('./ratings.csv', reader=reader)\n",
    "train_set = data.build_full_trainset()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 105
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 143903,
     "status": "ok",
     "timestamp": 1600232290196,
     "user": {
      "displayName": "yusheng zhou",
      "photoUrl": "",
      "userId": "10321925231562651610"
     },
     "user_tz": -480
    },
    "id": "vP7Yvmnp8y3P",
    "outputId": "62c73b46-7576-4463-e4b4-127f12047f40"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSE: 0.8724\n",
      "RMSE: 0.8720\n",
      "RMSE: 0.8725\n",
      "user: 196        item: 302        r_ui = 4.00   est = 4.34   {'was_impossible': False}\n",
      "145.8292853832245\n"
     ]
    }
   ],
   "source": [
    "# 使用funkSVD\n",
    "time1=time.time()\n",
    "algo = SVD(biased=False)\n",
    "# 定义K折交叉验证迭代器，K=3\n",
    "kf = KFold(n_splits=3)\n",
    "for trainset, testset in kf.split(data):\n",
    "    # 训练并预测\n",
    "    algo.fit(trainset)\n",
    "    predictions = algo.test(testset)\n",
    "    # 计算RMSE\n",
    "    accuracy.rmse(predictions, verbose=True)\n",
    "\n",
    "uid = str(196)\n",
    "iid = str(302)\n",
    "# 输出uid对iid的预测结果\n",
    "pred = algo.predict(uid, iid, r_ui=4, verbose=True)\n",
    "time2=time.time()\n",
    "print(time2-time1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 123
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 145288,
     "status": "ok",
     "timestamp": 1600232925370,
     "user": {
      "displayName": "yusheng zhou",
      "photoUrl": "",
      "userId": "10321925231562651610"
     },
     "user_tz": -480
    },
    "id": "bAqJciAr7xIt",
    "outputId": "9354afa7-73a3-4c2c-ec4b-89475ca4acd1"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSE: 0.8469\n",
      "RMSE: 0.8446\n",
      "RMSE: 0.8442\n",
      "user: 196        item: 302        r_ui = 4.00   est = 4.15   {'was_impossible': False}\n",
      "145.16541814804077\n"
     ]
    }
   ],
   "source": [
    "# 使用BiasSVD\n",
    "time1=time.time()\n",
    "algo = SVD(biased=True)\n",
    "# 定义K折交叉验证迭代器，K=3\n",
    "\n",
    "kf = KFold(n_splits=3)\n",
    "for trainset, testset in kf.split(data):\n",
    "    # 训练并预测\n",
    "    algo.fit(trainset)\n",
    "    predictions = algo.test(testset)\n",
    "    # 计算RMSE\n",
    "    accuracy.rmse(predictions, verbose=True)\n",
    "\n",
    "uid = str(196)\n",
    "iid = str(302)\n",
    "# 输出uid对iid的预测结果\n",
    "pred = algo.predict(uid, iid, r_ui=4, verbose=True)\n",
    "time2=time.time()\n",
    "print(time2-time1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 158
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 6726197,
     "status": "ok",
     "timestamp": 1600241000251,
     "user": {
      "displayName": "yusheng zhou",
      "photoUrl": "",
      "userId": "10321925231562651610"
     },
     "user_tz": -480
    },
    "id": "PduHmEnKTlub",
    "outputId": "8a2a667c-2ab7-479c-d5c3-6c90b0607a52"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSE: 0.8292\n",
      "RMSE: 0.8287\n",
      "RMSE: 0.8300\n",
      "user: 196        item: 302        r_ui = 4.00   est = 4.26   {'was_impossible': False}\n",
      "9043.746028900146\n"
     ]
    }
   ],
   "source": [
    "# 使用SVD++\n",
    "time1=time.time()\n",
    "algo = SVDpp()\n",
    "# 定义K折交叉验证迭代器，K=3\n",
    "kf = KFold(n_splits=3)\n",
    "for trainset, testset in kf.split(data):\n",
    "    # 训练并预测\n",
    "    algo.fit(trainset)\n",
    "    predictions = algo.test(testset)\n",
    "    # 计算RMSE\n",
    "    accuracy.rmse(predictions, verbose=True)\n",
    "\n",
    "uid = str(196)\n",
    "iid = str(302)\n",
    "# 输出uid对iid的预测结果\n",
    "pred = algo.predict(uid, iid, r_ui=4, verbose=True)\n",
    "time2=time.time()\n",
    "print(time2-time1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### deepFM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from sklearn.metrics import mean_squared_error\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "from sklearn import metrics\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "from deepctr.models import DeepFM\n",
    "from deepctr.feature_column import SparseFeat,get_feature_names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = pd.read_csv(\"ratings.csv\")\n",
    "sparse_features = [\"userId\", \"movieId\", 'timestamp']\n",
    "target = ['rating']\n",
    "\n",
    "# 对特征标签进行编码\n",
    "for feature in sparse_features:\n",
    "    lbe = LabelEncoder()\n",
    "    data[feature] = lbe.fit_transform(data[feature])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算每个特征中的 不同特征值的个数\n",
    "fixlen_feature_columns = [SparseFeat(feature, data[feature].nunique()) for feature in sparse_features]\n",
    "linear_feature_columns = fixlen_feature_columns\n",
    "dnn_feature_columns = fixlen_feature_columns\n",
    "feature_names = get_feature_names(linear_feature_columns + dnn_feature_columns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将数据集切分成训练集和测试集\n",
    "train, test = train_test_split(data, test_size=0.2)\n",
    "train_model_input = {name:train[name].values for name in feature_names}\n",
    "test_model_input = {name:test[name].values for name in feature_names}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2622/2622 [==============================] - 98s 37ms/step - loss: 0.9399 - mse: 0.9336 - val_loss: 0.7514 - val_mse: 0.7382\n"
     ]
    }
   ],
   "source": [
    "# 使用DeepFM进行训练\n",
    "model = DeepFM(linear_feature_columns, dnn_feature_columns, task='regression')\n",
    "model.compile(\"adam\", \"mse\", metrics=['mse'], )\n",
    "history = model.fit(train_model_input, train[target].values, batch_size=256, epochs=1, verbose=True, validation_split=0.2, )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4.436012 ],\n",
       "       [3.9129455],\n",
       "       [4.157041 ],\n",
       "       ...,\n",
       "       [3.0135837],\n",
       "       [3.823564 ],\n",
       "       [3.8273492]], dtype=float32)"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用DeepFM进行预测\n",
    "pred_ans = model.predict(test_model_input, batch_size=256)\n",
    "pred_ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test RMSE 0.8608716512930368\n"
     ]
    }
   ],
   "source": [
    "# 输出RMSE或MSE\n",
    "mse = round(mean_squared_error(test[target].values, pred_ans), 4)\n",
    "rmse = mse ** 0.5\n",
    "print(\"test RMSE\", rmse)"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "authorship_tag": "ABX9TyM7xKRs/82d3Y3R/7GFdMyp",
   "collapsed_sections": [],
   "name": "MovieLens.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
